package com.mindata.blockchain.block.check.local;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import com.mindata.blockchain.block.Block;
import com.mindata.blockchain.block.check.BlockChecker;
import com.mindata.blockchain.common.Sha256;
import com.mindata.blockchain.common.exception.TrustSDKException;
import com.mindata.blockchain.core.manager.DbBlockManager;
import com.mindata.blockchain.core.manager.PermissionManager;
import com.mindata.blockchain.core.requestbody.BlockRequestBody;
import com.mindata.blockchain.core.service.BlockService;

import cn.hutool.core.util.StrUtil;

/**
 * 使用本地存储的权限、Block信息对新来的block进行校验
 * 
 * @author wuweifeng wrote on 2018/3/13.
 */
@Component
public class DbBlockChecker implements BlockChecker {
	@Resource
	private DbBlockManager dbBlockManager;
	@Resource
	private PermissionManager permissionManager;

	@Resource
	private BlockService blockService;

	@Override
	public int checkNum(final Block block) {
		final Block localBlock = getLastBlock();
		int localNum = 0;
		if (localBlock != null) {
			localNum = localBlock.getBlockHeader().getNumber();
		}
		//本地区块+1等于新来的区块时才同意
		if (localNum + 1 == block.getBlockHeader().getNumber()) {
			//同意生成区块
			return 0;
		}

		//拒绝
		return -1;
	}

	@Override
	public int checkPermission(final Block block) {
		//校验对表的操作权限
		return permissionManager.checkPermission(block) ? 0 : -1;
	}

	@Override
	public int checkHash(final Block block) {
		final Block localLast = getLastBlock();
		//创世块可以，或者新块的prev等于本地的last hash也可以
		if (localLast == null && block.getBlockHeader().getHashPreviousBlock() == null) {
			return 0;
		}
		if (localLast != null && StrUtil.equals(localLast.getHash(), block.getBlockHeader().getHashPreviousBlock())) {
			return 0;
		}
		return -1;
	}

	@Override
	public int checkTime(final Block block) {
		final Block localBlock = getLastBlock();
		//新区块的生成时间比本地的还小
		if (localBlock != null && block.getBlockHeader().getTimeStamp() <= localBlock.getBlockHeader().getTimeStamp()) {
			//拒绝
			return -1;
		}
		return 0;
	}

	@Override
	public int checkSign(final Block block) {
		if (!checkBlockHashSign(block)) {
			return -1;
		}
		return 0;
	}

	private Block getLastBlock() {
		return dbBlockManager.getLastBlock();
	}

	public String checkBlock(final Block block) {
		if (!checkBlockHashSign(block)) {
			return block.getHash();
		}

		final String preHash = block.getBlockHeader().getHashPreviousBlock();
		if (preHash == null) {
			return null;
		}

		final Block preBlock = dbBlockManager.getBlockByHash(preHash);
		if (preBlock == null) {
			return block.getHash();
		}

		final int localNum = preBlock.getBlockHeader().getNumber();
		//当前区块+1等于下一个区块时才同意
		if (localNum + 1 != block.getBlockHeader().getNumber()) {
			return block.getHash();
		}
		if (block.getBlockHeader().getTimeStamp() <= preBlock.getBlockHeader().getTimeStamp()) {
			return block.getHash();
		}

		return null;
	}

	/**
	 * 检测区块签名及hash是否符合
	 * 
	 * @param block
	 * @return
	 */
	private boolean checkBlockHashSign(final Block block) {
		final BlockRequestBody blockRequestBody = new BlockRequestBody();
		blockRequestBody.setBlockBody(block.getBlockBody());
		blockRequestBody.setPublicKey(block.getBlockHeader().getPublicKey());
		try {
			if (blockService.check(blockRequestBody) != null) {
				return false;
			}
		} catch (final TrustSDKException e) {
			return false;
		}

		final String hash = Sha256.sha256(block.getBlockHeader().toString() + block.getBlockBody().toString());
		if (!StrUtil.equals(block.getHash(), hash)) {
			return false;
		}

		return true;
	}

}
